package acptTests;

import msgParser.Strings;

import org.junit.Before;
import org.junit.Test;

import tokenizer.StringMessage;
import java.util.concurrent.Semaphore;

	/*
	 * Torture Test
	 * Purpose: test the performance of all the different operations that
	 * are available for the clients it terms of response time and overall time.
	 * This test will attempt to create enormous amounts of data units (e.g. users)
	 * and request extreme amounts of operations on huge sets of information.
	 */

public class TortureTest extends ServerTest
{
	
	protected int testUserID;
	protected int adminID;
	protected int ForumID;
	protected int newSubForumID;
	protected int newPostID;
	protected int newReplyID;
	protected static final int forums = 1;		//we support up to forums forums
	protected static final int subs = 10;		//we support up to subs subforums per forum
	protected static final int users = 10;		//we support up to users users per forum
	protected static final int topics = 10;		//we support up to topics topics per subforum
	protected static final int reps = 10;		//we support up to reps repliess per topic
	protected int logsuccess;
	protected int regsuccess;
	protected int subsuccess;
	protected int topsuccess;
	protected int repsuccess;
	protected int[] regs;
	protected int[] logs;
	protected Thread[] userthreads;
	protected Thread[] subthreads;
	protected Thread[] topthreads;
	protected Thread[] repthreads;
	protected int[] ForumIDs;
	protected int[] userIDs;
	protected int[] subForumIDs;
	protected int[] topicIDs;
	protected int[] replyIDs;
	
	protected final Semaphore Sem = new Semaphore(1,true);
	@Before
	public synchronized void setUp()
	{	
		super.setUp();	
	}
	
	public String send(String str)
	{	
		return sp.processMessage(new StringMessage(str) , ch).toString();
	}
	
	
	
	public void init()
	{
		send("INIT_FORUM \0 superAdminUser \0 myPass");
		ForumIDs = new int[forums];
		userIDs = new int[users*forums];
		subForumIDs = new int[subs*forums];
		topicIDs = new int[topics*subs*forums];
		replyIDs = new int[reps*topics*subs*forums];
	}
	
	public String loginSuperAdmin()
	{
		return send("ADMIN_LOGIN \0 superAdminUser \0 myPass");
	}
	
	public String logout()
	{
		return send("LOGOUT");
	}
	
	public String loginUser(int forumID)
	{
		String result = send("LOG_IN \0 testreg \0 pass123 \0 " + forumID);
		adminID = Integer.parseInt(getWord(result.toString(), 2));
		return result;
	}
	
	public String register(int forumID)
	{
		String result = send("REGISTER \0 testreg \0 pass123 \0 maximdzagoev@gmail.com" + Math.random() +"\0" + forumID);
		adminID = Integer.parseInt(getWord(result.toString(), 1));
		return result;
	}
	
	@Test
	public void testNumOfForums()
	{
		init();
		loginSuperAdmin();
		String Policies = Strings.IMMEDIATE_NOTIFY+"\0" + Strings.FORUM_MEMBERS_NOTIFY +"\0"+ 1 +"\0" +Strings.AUTHOR_FORUM_DELETE_POST+"\0"
				+Strings.MIN_POST_ADD_MODERATOR+"\0"+Strings.CANNOT_REMOVE_SINGLE_MODERATOR+"\0"+ 
				Strings.VALID_EMAIL_SECURITY+"\0" +Strings.REJECT_BAD_WORDS;
		
		for (int i=0; i<forums; i++)
		{
			String forum = send("ADD_FORUM \0 General Discussion" +i+ "\0 " + adminID + " \0 "+ Policies);
			assertTrue(forum.startsWith("FORUM_ADDED"));
			System.out.println(forum);
			ForumIDs[i] = Integer.parseInt(getWord(forum, 1));
		}
		//send("ADD_SUBFORUM \0 myLove \0 1 \0" + adminID);
	}
	
	@Test
	public void testNumOfUsers() throws InterruptedException
	{
		testNumOfForums();
		regs = new int[users*forums];
		logs = new int[users*forums];
		userthreads = new Thread[users*forums];
		int t = 0;
		for (int j=0; j<forums; j++)
		{
			for (int i=0; i<users; i++)
			{
			Thread th = new Thread(new User(i,j));
			userthreads[t] = th;
			t++;
			th.start();
			}
		}
		
		for (int k=0; k<users*forums; k++) 
		{
			userthreads[k].join();
		}
		System.out.println("hi there " +logsuccess+" " + regsuccess);
		assertEquals(users*forums , regsuccess);
		assertEquals(users*forums , logsuccess);
	}
	
	
		@Test
		public void testNumOfSubforums() throws InterruptedException
		{
			init();
			testNumOfForums();
			int t = 0;
			subthreads = new Thread[subs*forums];
			for (int j=0; j<forums; j++)
			{
				for (int i=0; i<subs; i++)
				{
					Thread th = new Thread(new Subforum(t , "Cars"+i+j , ForumIDs[j] , adminID));
					subthreads[t] = th;
					t++;
					th.start();
				}
			}
			for (int k=0; k<subs*forums; k++) 
			{
				subthreads[k].join();
			}
			System.out.println("hi there " +subsuccess);
			assertEquals(subs*forums , subsuccess);
		}
		
	
	@Test
	public void testNumOfTopics() throws InterruptedException
	{
		testNumOfSubforums();
		//testNumOfUsers();
		topthreads = new Thread[subs*forums*topics];
		int t = 0;
		for (int m=0; m<forums; m++)
		{
			for (int j=0; j<subs; j++)
			{
				for (int i=0; i<topics; i++)
				{
				Thread th = new Thread(new Topic(t , "hello mate" , "how was your day?" , subForumIDs[j]));
				topthreads[t] = th;
				t++;
				th.start();
				}
			}
		}
		for (int k=0; k<topics*subs*forums; k++) 
		{
			topthreads[k].join();
		}
		System.out.println("hi there " +topsuccess);
		assertEquals(topics*subs*forums , topsuccess);
	}
	
	@Test
	public void testnumOfReplies() throws InterruptedException
	{
		testNumOfTopics();
		repthreads = new Thread[reps*subs*forums*topics];
		int t = 0;
		for (int n=0; n<forums; n++)
		{
			for (int m=0; m<subs; m++)
			{
				for (int j=0; j<topics; j++)
				{
					for (int i=0; i<reps; i++)
					{
						Thread th = new Thread(new Reply(t ,  "Nothing much, what about you?" , topicIDs[j]));
						repthreads[t] = th;
						t++;
						th.start();
					}
				}
			}
		}
		
		for (int k=0; k<reps*topics*subs*forums; k++) 
		{
			repthreads[k].join();
		}
		System.out.println("hello " +repsuccess);
		assertEquals(reps*topics*subs*forums , repsuccess);
	}
	
	
	private synchronized void regupdate()
	{
		regsuccess++;
	}
	private synchronized void logupdate()
	{
		logsuccess++;
	}
	private synchronized void subupdate()
	{
		subsuccess++;
	}
	private synchronized void topupdate()
	{
		topsuccess++;
	}
	private synchronized void repupdate()
	{
		repsuccess++;
	}
	
	private class User implements Runnable
	{
		int id;
		int forum;
		
		public User(int arg, int fm)
		{id = arg;
		forum = fm;}
		@Override
		public void run() 
		{	
			try {Sem.acquire();} 
			catch (InterruptedException e) {System.out.println("unable to acquire");}
			setUp();
			System.out.println(id+" "+ForumIDs[forum]);
			String result1 = send("REGISTER \0 user"+ id+logsuccess +" \0 " + id + "\0 max@max.com"+ id+logsuccess+ " \0" + ForumIDs[forum]);
			System.out.println(result1);
			regs[id] = Integer.parseInt(getWord(result1, 1));
			String result2 = send("LOG_IN \0 user"+ id+logsuccess +" \0 " + id + " \0" + ForumIDs[forum]);
			System.out.println(result2);
			logs[id] = Integer.parseInt(getWord(result2, 1));
			userIDs[id] = logs[id];
			
			if (result1.startsWith("REGISTERED")) regupdate();
			if (result2.startsWith("LOGGED_IN")) logupdate();	
		
			Sem.release();
		}
		
	}
	
	private class Subforum implements Runnable
	{
		int id;	
		String kotar;
		int fid;
		int mod;
		
		public Subforum(int i,String title, int ForumID , int ModID)
		{
			id = i;
			kotar = title;
			fid = ForumID;
			mod = ModID;
		}
		@Override
		public void run() {
			try {Sem.acquire();} 
			catch (InterruptedException e) {System.out.println("unable to acquire");}
			setUp();
			loginSuperAdmin();
			String result1 = send("ADD_SUBFORUM\0"+ kotar + "\0" + fid +" \0 " + 661);
			System.out.println("****"+result1);
			subForumIDs[id] = Integer.parseInt(getWord(result1, 1));
			
			if (result1.startsWith("SUBFORUM_ADDED")) subupdate();
	
			Sem.release();
		}
		
	}
	
	private class Topic implements Runnable
	{
		int id;	
		String title;
		String text;
		int sid;
		
		public Topic(int id,String title, String text , int sid)
		{
			this.id = id;
			this.title = title;
			this.text = text;
			this.sid = sid;
		}
		@Override
		public void run() {
			try {Sem.acquire();} 
			catch (InterruptedException e) {System.out.println("unable to acquire");}
		
			
			String result1 = send("ADD_TOPIC\0"+ title + "\0" + text +" \0 " + sid);
			topicIDs[id] = Integer.parseInt(getWord(result1, 1));
			
			if (result1.startsWith("TOPIC_ADDED")) topupdate();
	
			Sem.release();
		}
		
	}
	
	private class Reply implements Runnable
	{
		int id;	
		String text;
		int tid;
		
		public Reply(int id, String text , int tid)
		{
			this.id = id;
			this.text = text;
			this.tid = tid;
		}
		@Override
		public void run() {
			try {Sem.acquire();} 
			catch (InterruptedException e) {System.out.println("unable to acquire");}
		
			
			String result1 = send("ADD_REPLY\0" + text +" \0 " + tid);
			replyIDs[id] = Integer.parseInt(getWord(result1, 1));
			
			if (result1.startsWith("REPLY_ADDED")) repupdate();
			
			Sem.release();
		}
		
	}
	
}
